import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class TcpEchoServer {
        private ServerSocket serverSocket = null;
        // 这个操作就会绑定端⼝号
        public TcpEchoServer(int port) throws IOException {
            serverSocket = new ServerSocket(port);
        }
        // 启动服务器
        public void start() throws IOException {
            System.out.println("服务器启动!");
            while (true) {
                Socket clientSocket = serverSocket.accept();
                processConnection(clientSocket);
            }
        }
        // 通过这个⽅法来处理⼀个连接的逻辑.
        private void processConnection(Socket clientSocket) {
            System.out.printf("[%s:%d] 客⼾端上线!\n", clientSocket.getInetAddress());
                    // 接下来就可以读取请求, 根据请求计算响应, 返回响应三步⾛了.
                    // Socket 对象内部包含了两个字节流对象, 可以把这俩字节流对象获取到, 完成后续的读写
            try (InputStream inputStream = clientSocket.getInputStream();
                 OutputStream outputStream = clientSocket.getOutputStream()) {
                // ⼀次连接中, 可能会涉及到多次请求/响应
                while (true) {
                    // 1. 读取请求并解析. 为了读取⽅便, 直接使⽤ Scanner
                    Scanner scanner = new Scanner(inputStream);
                    if (!scanner.hasNext()) {
                        // 读取完毕, 客⼾端下线.
                        System.out.printf("[%s:%d] 客⼾端下线!\n", clientSocket.getInetAddress());
                        break;
                    }
                    // 这个代码暗含⼀个约定, 客⼾端发过来的请求, 得是⽂本数据, 同时, 还得带有
                    String request = scanner.next();
                    // 2. 根据请求计算响应
                    String response = process(request);
                    // 3. 把响应写回给客⼾端. 把 OutputStream 使⽤ PrinterWriter 包裹⼀下
                    PrintWriter writer = new PrintWriter(outputStream);
                    // 使⽤ PrintWriter 的 println ⽅法, 把响应返回给客⼾端.
                    // 此处⽤ println, ⽽不是 print 就是为了在结尾加上 \n . ⽅便客⼾端
                    writer.println(response);
                    // 这⾥还需要加⼀个 "刷新缓冲区" 操作.
                    writer.flush();
                    // ⽇志, 打印当前的请求详情.
                    System.out.printf("[%s:%d] req: %s, resp: %s\n", clientSocket.getInetAddress());
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                // 在 finally 中加上 close 操作, 确保当前 socket 被及时关闭!!
                try {
                    clientSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        public String process(String request) {
            return request;
        }
        public static void main(String[] args) throws IOException {
            TcpEchoServer server = new TcpEchoServer(9090);
            server.start();
        }
}
